#ifndef __CHATSERVICE_HPP__
#define __CHATSERVICE_HPP__

#include <functional>
#include <unordered_map>
#include <string>
#include <mutex>
#include <muduo/net/TcpConnection.h>
#include "usermodel.hpp"
#include "offlinemsgmodel.hpp"
#include "friendmodel.hpp"
#include "groupmodel.hpp"
#include "../thirdparty/json.hpp"
#include "redis.hpp"

using json = nlohmann::json;
using namespace muduo;
using namespace muduo::net;

using MsgHandler = std::function<void(const TcpConnectionPtr &, json &, Timestamp)>;

// 业务处理类(单例模式)
class ChatService
{
public:
    // 获取单例对象
    static ChatService *instance();

    // 服务器异常退出，重置数据库中在线用户的状态
    void reset();

    // 处理注册业务
    void reg(const TcpConnectionPtr &conn, json &js, Timestamp time);

    // 处理登录业务
    void login(const TcpConnectionPtr &conn, json &js, Timestamp time);

    // 处理客户端注销业务
    void loginout(const TcpConnectionPtr &conn, json &js, Timestamp time);

    // 处理点对点通信业务
    void oneChat(const TcpConnectionPtr &conn, json &js, Timestamp time);

    // 添加好友业务
    void addFriend(const TcpConnectionPtr &conn, json &js, Timestamp time);

    // 创建群组业务
    void createGroup(const TcpConnectionPtr &conn, json &js, Timestamp time);

    // 加入群组业务
    void addGroup(const TcpConnectionPtr &conn, json &js, Timestamp time);

    // 群组聊天业务
    void groupChat(const TcpConnectionPtr &conn, json &js, Timestamp time);

    // 处理客户端用户异常退出
    void clientQuitException(const TcpConnectionPtr &conn, json js = json(), Timestamp time = Timestamp());

    // 当不同服务器中订阅了channel后有消息到来，调用回调处理
    void handleRedisSubscribeMsg(int userid, std::string msg);

    // 获取消息id对应的事件处理回调
    MsgHandler getHandler(int msgid);

private:
    ChatService();

private:
    // 消息id与其对应的回调函数
    std::unordered_map<int, MsgHandler> _msgHandlerMap;

    // 数据操作类
    UserModel _userModel;
    OfflineMsgModel _offlineMsgModel;
    FriendModel _friendModel;
    GroupModel _groupModel;

    // 记录用户连接的信息<用户id，连接Ptr>
    std::unordered_map<int, TcpConnectionPtr> _userConnMap;

    // 定义互斥锁，保护_userConnMap的线程安全
    std::mutex _connMutex;

    // redis操作对象
    Redis _redis;
};

#endif